﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Mclib
{
	/// <summary>
	/// The data structure for data.  "Data.InferentialPower.XML"
	/// </summary>
	public class Data
	{
		/// <summary>
		/// The name of the data set.
		/// </summary>
		public string Name;
		/// <summary>
		/// General comments about the data.
		/// </summary>
		public string Comments;
		/// <summary>
		/// The identifiers (e.g. category identifier, validation group identifier)
		/// for each datum.  Group numbers are 1-based integers.
		/// </summary>
		public int[,] Id;
		/// <summary>
		/// The labels for each column of Id.
		/// </summary>
		public string[] IdName;
		/// <summary>
		/// The labels associated with nominal value for a column of Id.
		/// </summary>
		public string[][] IdNames;
		/// <summary>
		/// The number of unique Id values that are enumerated in each column of this.Id.
		/// </summary>
		public int[] IdUnique;
		/// <summary>
		/// The spatial coordinates for each datum.
		/// </summary>
		public float[,] Coord;
		/// <summary>
		/// The labels for each column (axis) of coordinates.
		/// </summary>
		public string[] CoordLabels;
	}
	/// <summary>
	/// This represents the data (constructed based on an instance of the Data class) organized so that categorization algorithms can efficiently process the data.
	/// </summary>
	public class CatData
	{
		/// <summary>
		/// The row-number of each categorized spatial coordinate (relative to the original instance of the Data class).
		/// </summary>
		public int[][] IdRow;
		/// <summary>
		/// The number of samples in each category.
		/// </summary>
		public int[] N;
		/// <summary>
		/// The spatial coordinates separated by category.
		/// </summary>
		public double[][,] X;
		/// <summary>
		/// Descriptive statistics for each category of data.
		/// </summary>
		public BasicStatistics[] Stats;
		/// <summary>
		/// The instance of Data used to create this instance.
		/// </summary>
		public Data OriginalData;
		/// <summary>
		/// The zero-based index into the column of OriginalData.Id[,_] by which category membership is defined.
		/// </summary>
		public int ColumnId;
		/// <summary>
		/// The zero-based indices into the columns of OriginalData.Coord[,_] used for this instance.
		/// </summary>
		public int[] ColumnsCoord;
		/// <summary>
		/// Constructs an instance derived from an instance of Data where the categories are defined by the specified column of Id.
		/// </summary>
		/// <param name="Data">The Data structure from which to extract data.</param>
		/// <param name="ColumnId">The column of OriginalData.Id[,_] by which to define category membership.</param>
		/// <param name="ColumnsCoord">The indices into the colums of OriginalData.Coord[,_].</param>
		public CatData(Data OriginalData,int ColumnId,int[] ColumnsCoord)
		{
			//	Set member variables
			this.ColumnsCoord = ColumnsCoord;
			this.ColumnId = ColumnId;
			this.OriginalData = OriginalData;

			//	Initialize member variables
			IdRow = new int[OriginalData.IdUnique[ColumnId]][];
			N = new int[OriginalData.IdUnique[ColumnId]];
			X = new double[OriginalData.IdUnique[ColumnId]][,];
			int nData = OriginalData.Coord.GetLength(0);
			int iDatum,iCat,iDim;
			int[] ctRows = new int[N.Length];

			//	Count the number of samples from each category.
			for (iDatum=0; iDatum<nData; iDatum++)
				N[OriginalData.Id[iDatum,ColumnId]-1]++;

			//	Initialize memory
			for (iCat=0; iCat<N.Length; iCat++)
			{
				IdRow[iCat] = new int[N[iCat]];
				X[iCat] = new double[N[iCat],this.ColumnsCoord.Length];
			}

			//	For each datum, store the coordinates and store a reference to the row of OriginalData.Coord and OriginalData.Id of the datum.
			for (iDatum=0; iDatum<nData; iDatum++)
			{
				iCat = OriginalData.Id[iDatum,ColumnId]-1;
				IdRow[iCat][ctRows[iCat]]=iDatum;
				for (iDim=0; iDim<ColumnsCoord.Length; iDim++)
					X[iCat][ctRows[iCat],iDim] = OriginalData.Coord[iDatum,ColumnsCoord[iDim]];
				ctRows[iCat]++;
			}

			//	Calculate statistics for each category
			Stats = new BasicStatistics[X.Length];
			for (iCat=0; iCat<Stats.Length; iCat++)
				Stats[iCat] = new BasicStatistics(X[iCat]);
		}
	}
	/// <summary>
	/// A class for statistics on Data.
	/// </summary>
	public class BasicStatistics
	{
		/// <summary>
		/// The mean of the data.
		/// </summary>
		public double[] Mean;
		/// <summary>
		/// The covariance matrix of the data.
		/// </summary>
		public double[,] Cov;
		/// <summary>
		/// Measures stats of the given data.
		/// </summary>
		/// <param name="x"></param>
		public BasicStatistics(double[,] x)
		{
			int nDims = x.GetLength(1);
			int nData = x.GetLength(0);
			int iRow, iDim, jDim;
			double[] xx = new double[nDims];
			Mean = new double[nDims];
			Cov = new double[nDims,nDims];

			//------------------------------------------------------------------------------
			//	Compute the mean
			//------------------------------------------------------------------------------
			for (iRow=0; iRow<nData; iRow++)
				for (iDim=0; iDim<nDims; )
					Mean[iDim++] += x[iRow,iDim];
			for (iDim=0; iDim<nDims; )
				Mean[iDim++] /= (double)nData;
			//------------------------------------------------------------------------------

			//------------------------------------------------------------------------------
			//	Compute upper-right triangle of covariance matrix.
			//------------------------------------------------------------------------------
			for (iRow=0; iRow<nData; iRow++)
			{
				// For each column of cov matrix
				for (jDim=0; jDim<nDims; jDim++)
				{
					xx[jDim]=x[iRow,jDim]-Mean[jDim];
					//	For each row less than or equal the current column
					for (iDim=jDim; iDim>=0; iDim--)
						Cov[iDim,jDim] += xx[iDim]*xx[jDim];
				}
			}
			for (jDim=0; jDim<nDims; jDim++)
				for (iDim=jDim; iDim>=0; iDim--)
					Cov[iDim,jDim] /= (double)(nData-1);
			//------------------------------------------------------------------------------
		}
	}
}